#include "Graph.h"
#include <math.h>
using namespace std;

void Graph::InputLair(std::ifstream &fi)
{
	int id, time, money;
	string decrypt, name;
	Lair lair;

	while (!fi.eof())
	{
		
		fi >> id;
		fi >> money;
		fi >>decrypt;
		fi >> time;
		fi >> name;

		lair = Lair(id, money, decrypt, time, name);
		lstLair.push_back(lair);
	}
}

void Graph::InputRobbery(std::ifstream &fi)
{
	string str;

	while (!fi.eof())
	{
		fi >> str;
		lstRobbery.push_back(str);
	}
}

void Graph::InputMap(std::ifstream &fi)
{
	fi >> N;
	fi >> StartY >> StartX;
	fi >> EndY >> EndX;
	Matrix.resize(N);
	for (int i = 0; i < N; i++)
		Matrix[i].resize(N, 0);

	int id, x, y, index;
	while (!fi.eof())
	{
		fi >> id >> y >> x;
		Matrix[x][y] = id;
		index = GetLairIndex(id);
		lstLair[index].X = x;
		lstLair[index].Y = y;
	}
}

void Graph::Output(std::ofstream &fo)
{
}

void Graph::Output()
{
	for (int i = 0; i < lstLair.size(); i++)
	{
		cout << lstLair[i].ID << " - " << lstLair[i].TotalMoney << " - " << lstLair[i].DecryptedKey << " - " << lstLair[i].AlarmTriggerTime << " - " << lstLair[i].Name <<  " - " << lstLair[i].X << " - " << lstLair[i].Y << "\n";
	}

	cout << "\n\n";

	for (int i = 0; i < lstRobbery.size(); i++)
	{
		cout << lstRobbery[i] << "\n";
	}

	cout << "\n\n";

	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			cout << Matrix[i][j] << " ";
		}
		cout << "\n";
	}

	cout << "\n\n";

	for (int i = 0; i < lstRobbery.size(); i++)
	{
		cout << Decrypt(lstRobbery[i]) << "\n";
	}
}

string Graph::Decrypt(string encrypted)
{
	int i = 0;
	while (i < (encrypted.length() - 1))
	{
		if (encrypted[i] == encrypted[i + 1])
		{
			encrypted.erase(i + 1, 1);
		}
		else
		{
			i++;
		}
	}

	string str = encrypted.substr(0, 3);
	i = encrypted.find(str);
	while (i >= 0)
	{
		encrypted.erase(i, 3);
		i = encrypted.find(str);
	}

	if (encrypted.substr(0, 2) == encrypted.substr(encrypted.length() - 2, 2))
	{
		encrypted.erase(0, 2);
		encrypted.erase(encrypted.length() - 2, 2);
		for (int j = 0; j < encrypted.length(); j++)
		{
			encrypted[j] += 3;
		}
	}
	else
	{
		encrypted.erase(0, 2);
		encrypted.erase(encrypted.length() - 2, 2);
		for (int j = 0; j < encrypted.length(); j++)
		{
			encrypted[j] += 5;
		}
	}
	return encrypted;
}

void Graph::Rob()
{
	fstream fb("bounty.txt", ios::out);

	double totalDistance = 0.0;
	int totalBounty = 0;
	int curX = StartX;
	int curY = StartY;
	
	vector<bool> visited(lstLair.size());
	for(int i = 0; i < visited.size(); i++)
	{
		visited[i] = false;
	}
	int index = -1;
	int numVisited = 0;
	while(true)
	{
		double minDistance;
		int minPos = -1;
		minDistance = 100000;
		for(int i = 0;  i < lstLair.size(); i++)
		{
			if(visited[i] == false)
			{
				double distance  = CountDistance(curX, curY, lstLair[i].X, lstLair[i].Y);
				if(distance < minDistance)
				{
					minDistance = distance;
					index = i;
				}
			}
		}
		visited[index] = true;
		if(numVisited == lstLair.size())
		{
			
			totalDistance = totalDistance + CountDistance(lstLair[index].X, lstLair[index].Y, this->EndX, this->EndY);
			cout << totalDistance << endl;
			fb << "Move from (" << curY << ", " << curX << ") to (" << this->EndX << ", " << this->EndY << ")" << endl;
			fb << "Made it to safety!" << endl;	
			fb << "Total distance traveled: " << totalDistance << " miles"<< endl;
			fb << "Total bounty given to charity: $" << totalBounty << endl;
			break;
		}

		numVisited++;
		fb << "Move from (" << curY << ", " << curX << ") to (" << lstLair[index].X << ", " << lstLair[index].Y << ")" << endl;
		fb << "Robber lair " << lstLair[index].Name << "and stole $" << lstLair[index].TotalMoney << endl;
		curX = lstLair[index].X;
		curY = lstLair[index].Y;
		totalDistance = totalDistance + minDistance;
		totalBounty += lstLair[index].TotalMoney;
	}
	
}
void Graph::ProcessDecryptLair()
	{
		fstream ff("failure.txt", ios::out);	
		for(int i = 0; i < lstLair.size(); i++)
		{

			string result = Decrypt(lstRobbery[i]);
			if(result != lstLair[i].DecryptedKey)
			{
				ff << lstLair[i].ID << "\t" << "incorrected decrypted key: " << result << endl;
				lstLair.erase(lstLair.begin() + i);
				lstRobbery.erase(lstRobbery.begin() + i);

				i--;
				
			} else {
				if(lstRobbery[i].size() > lstLair[i].AlarmTriggerTime)
				{
					ff << lstLair[i].ID << "\t" << "decryption time too long: " << lstRobbery[i].length() << endl;
					lstLair.erase(lstLair.begin() + i);
					lstRobbery.erase(lstRobbery.begin() + i);
					i--;
					
				}
			}
		}
	}
double Graph::CountDistance(int StartPointX, int StartPointY, int EndPointX, int EndPointY)
{
	return sqrt((double)((EndPointX - StartPointX) * (EndPointX - StartPointX)) + (double)((EndPointY - StartPointY) * (EndPointY - StartPointY))); 
}

int Graph::GetLairIndex(int id)
{
	for (int i = 0; i < lstLair.size(); i++)
	{
		if (lstLair[i].ID == id)
			return i;
	}
	return 0;
}